home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / GRAPHICS / FAKE_MOD.ZIP / FAKEMODE.DOC < prev    next >
Encoding:
Text File  |  1994-05-16  |  19.8 KB  |  624 lines

  1.            ******************************************
  2.            ** OFFICIAL FakeMode DOCUMENTATION FILE **
  3.            ******************************************
  4.  
  5.            written by Yaka/Xography in April/May 1994
  6.           orthographic supervision by Sandman/Valhalla
  7.  
  8.  
  9.  
  10. Hi, Dudes;
  11.  
  12. I was asked about FakeMode and how I did it so often I thought I had to write
  13. a documentation about it. This documentation is written for all those who
  14. want to understand the principles behind FakeMode or even want to program
  15. the mode themselves. Feel free to use FakeMode in your own programs.
  16. There may be mistakes in this text, so you are self responsible for what may
  17. happen when you try to code FakeMode!
  18. There are a complete library with FakeMode routines and an example program
  19. for its use included with this doc. They were originally made for BC 3.1, but
  20. should be usable with other languages too. Just experiment with them!
  21.  
  22.  
  23. ---------
  24. CONTENTS:
  25. ---------
  26.  
  27. Chapter 1. What is FakeMode?
  28. Chapter 2. The techniques behind FakeMode and how to program it
  29. Chapter 3. Information about the program included
  30. Chapter 4. Literature
  31.  
  32.  
  33.  
  34. -----------------------------
  35. CHAPTER 1: What is FakeMode?
  36. -----------------------------
  37.  
  38. FakeMode is a way to setup standard VGA cards so they are able to display
  39. more than 256 colors. I invented this mode in Xography's "Party93 Report"
  40. which was released in April 1994. So what is FakeMode good for?
  41.  
  42. PRO FakeMode:
  43. -You have a screen resolution of 320x400
  44. -You have 3840 (fixed) colors on standard VGA's
  45.  
  46. CONTRA FakeMode:
  47. - It is slow
  48. - The screen flickers a little
  49. - You need the timer interrupt
  50. - It works only on register compatible VGAs
  51. - setting pixels is difficult
  52. - the palette is fixed; so you can't choose the colors freely from 262144
  53.  
  54.  
  55. I think Fakemode is not useful for animations because:
  56. - you have to output 4 bytes to set 1 320x200 - Pixel  ( -> slow)
  57. - screen memory access is rather complicated
  58. - slow movements will interfere with page flipping, this looks ugly
  59.    (Hm, perhaps you'll find a way how to avoid this?)
  60.  
  61.  
  62.  
  63. -----------------------------------------
  64. CHAPTER 2: The techniques behind FakeMode
  65. -----------------------------------------
  66.  
  67. FakeMode is achieved by combination of several means:
  68.  
  69. - Use Y-mode (320x400 at 256 colors and 2 pages)
  70. - Flip between the 2 pages at every vertical retrace
  71. - select the palette colors wisely
  72. - set pixel data in a special way.
  73.  
  74.  
  75. *** 2.1 Y-Mode
  76.  
  77. Y-Mode (similar to X-mode) is a video mode for register compatible VGA cards,
  78. that pushes resolution up to 320x400 at still 256 colors and 2 pages! The
  79. disadvantage compared to standard mode 13h (320x200, 256col, 1 page) is that
  80. memory access is not so easy anymore (the pixels are split up in bitplanes).
  81. Here's the code I use to setup Y-Mode for FakedMode (in TASM 3.1) [1]:
  82.  
  83. ********************************************
  84.   _F_initgraph PROC
  85.     push di                     ;//save DI because of BC (I call from BC)
  86.     mov ax,0f00h                ;//Get old videomode...
  87.     int 10h
  88.     mov oldvideomode,al         ;//...and save it (define oldvideomode!)
  89.  
  90.     mov ax,0013h                ;//initialize normal Mode 13h
  91.     int 10h
  92.  
  93.     mov dx,3ceh                 ;//select Graphics Controller...
  94.     mov al,5                    ;//...Graphics Mode Register
  95.     out dx,al
  96.     inc dx
  97.     in al,dx
  98.     and al,11101111b            ;//switch off ODD/EVEN mode
  99.     out dx,al
  100.     dec dx
  101.  
  102.     mov al,6                    ;//...Miscellaneous Register
  103.     out dx,al
  104.     inc dx
  105.     in al,dx
  106.     and al,11111101b            ;//switch off ODD/EVEN mode here, too
  107.     out dx,al
  108.  
  109.     mov dx,3c4h                 ;//select Sequencer Controller...
  110.     mov al,4                    ;//...Memory Mode Register
  111.     out dx,al
  112.     inc dx
  113.     in al,dx
  114.     and al,11110111b            ;//use linear adressing
  115.     or al,4
  116.     out dx,al
  117.  
  118.     mov ax,0a000h               ;//access Video Memory
  119.     mov es,ax
  120.     xor di,di
  121.     mov ax,di
  122.     mov cx,8000h
  123.     rep stosw                   ;//clear Screen
  124.  
  125.     mov dx,3d4h                 ;//select CRT Controller...
  126.     mov al,9                    ;//...Maximum Scan Line Register
  127.     out dx,al
  128.     inc dx
  129.     in al,dx
  130.     and al,01110000b            ;//select 400 lines
  131.     out dx,al
  132.     dec dx
  133.  
  134.     mov al,14h                  ;//...Underline Location Register
  135.     out dx,al
  136.     inc dx
  137.     in al,dx
  138.     and al,10111111b            ;//switch off Doubleword-Mode
  139.     out dx,al
  140.     dec dx
  141.  
  142.     mov al,17h                  ;//...Mode Control Register
  143.     out dx,al
  144.     inc dx
  145.     in al,dx                    ;//select Word-Mode (normally: Bytemode)
  146.     and al,10111111b            ;//normally: or al,01000000b
  147.     out dx,al
  148.  
  149.     call initpalette            ;//call to palette setup routine (for FakeMode)
  150.  
  151.     call inittimer              ;//call to timer setup routine (for FakeMode)
  152.     pop di                      ;//restore value of di
  153.     ret
  154.   _F_initgraph ENDP
  155. ************************************
  156.  
  157. That's it. I modified the original routine a bit as I keep WordMode;
  158. it's because it is easier to write FakeMode pixels in WordMode.
  159. You can return to textmode or other graphics modes by normal BIOS function
  160. call (int 10h, Fkt 0).
  161. The calls to 'initpalette' and 'inittimer' are necessary to install FakeMode
  162. and are not part of Y-Mode installation.
  163.  
  164.  
  165. *** 2.2 Page Flipping
  166.  
  167. This is best done (I think) by synchronizing the timer interrupt with the
  168. screen. Just before the vertical retrace appears, the interrupt is called.
  169. The interrupt handler routine should now set the screen offset address to
  170. its new value and wait for the vertical retrace. Then it should reprogram
  171. the timer and return to the main program. When the vertical retrace occurs,
  172. the new offset address is loaded in the internal registers of the VGA card
  173. and invokes the next screen update. See [1], ([2]), [3].
  174.  
  175. So we'll just have to:
  176.   - hook the timer interrupt
  177.   - write our own interrupt handler
  178.   - synchronize the timer interrupt with the screen
  179.   - still call system timer routine at 18.2 Hz from interrupt handler
  180.   - program the timer chip to achieve MonoFlop mode.
  181.  
  182. What could be simpler? :)
  183.  
  184.  
  185. *** 2.2.1 Hooking/Dehooking the timer interrupt,
  186.       Synchronization with the screen
  187.  
  188. Hooking an interrupt is quite easy; DOS interupt 21h has got functions to
  189. handle interrupt hooking (see below, routine inittimer).
  190. To synchronize the timer int with the screen, I first set the interrupt speed
  191. much faster than the screen (256 Hz) and use a handler that counts up a
  192. variable 'count'. Then I wait for a vertical retrace and let the timer run.
  193. When 'count' has changed at next vertical retrace, the timer still is too
  194. fast. I lower speed and try again, until 'count' doesn't change between start
  195. of timer and next vertical retrace. Then I know that with this speed, I'm just
  196. below the minimal speed. I increase it a little and now I know how long I
  197. have to wait aproximately between 2 timer int calls. Of course the value isn't
  198. exact, so I have to synchronize every interrupt call for new; that's done
  199. by the interrupt handler discussed below.
  200. The routine 'closetimer' should be called when you leave FakeMode; it stops
  201. the timer int and puts everything back to normal.
  202.  
  203.  
  204. ************************************
  205. synchroint PROC                 ;// This interrupt handler is used for
  206.   push ax                       ;// screen synchronization.
  207.   mov ax,counter
  208.   inc ax                        ;// just count up 'counter'...
  209.   mov counter,ax
  210.   mov al,20h                    ;// send EOI to interrupt controller...
  211.   out 20h,al
  212.   pop ax
  213.   iret                          ;// return from interrupt handler
  214. synchroint ENDP
  215.  
  216. inittimer PROC                  ;// This routine is called when FakeMode is
  217.   push di                       ;// installed. it initializes & synchronizes
  218.   mov ax,1234h                  ;// the timer
  219.   mov currentfloptime,ax        ;// start with 256 Hz
  220.  
  221.   mov ax,3508h                  ;//save old Interrupt 08
  222.   int 21h
  223.   mov alterint08,bx
  224.   mov alterint08+2,es
  225.  
  226.   xor ax,ax                     ;//redirect Int. 08 to Synchronisation Rout.
  227.   mov es,ax
  228.   mov di,08h*4                  ;// this is the other method to access
  229.   cli                           ;// interrupt vectors: via the interrupt table
  230.   cld
  231.   mov ax,offset synchroint
  232.   stosw
  233.   mov ax,cs
  234.   stosw
  235.   sti
  236.  
  237.   ;//------ synchronize timer with screen
  238.  
  239.   mov dx,3dah                   ;//Wait for End of Retrace
  240. s1endretjmp:
  241.   in al,dx
  242.   and al,00001000b
  243.   jnz s1endretjmp
  244. s1retjmp:                       ;//Wait for Retrace
  245.   in al,dx
  246.   and al,00001000b
  247.   jz s1retjmp
  248.  
  249. synchroback:                    ;//now we can start measurement...
  250.  
  251.     mov al,36h                  ;//start Systemtimer in Rectangle Mode
  252.     out 43h,al
  253.     mov ax,currentfloptime
  254.     out 40h,al
  255.     mov al,ah
  256.     out 40h,al
  257.  
  258.     mov ax,0                    ;//reset counter. counter is increased
  259.     mov counter, ax             ;//by interrupt routine
  260.  
  261.     mov dx,3dah                 ;//Wait for End of Retrace
  262.   s2endretjmp:
  263.       in al,dx
  264.       and al,00001000b
  265.     jnz s2endretjmp
  266.   s2retjmp:                     ;//Wait for Retrace
  267.       in al,dx
  268.       and al,00001000b
  269.     jz s2retjmp
  270.  
  271.     mov ax,counter              ;//did interrupt still occur?
  272.     cmp ax,0
  273.     je fertig                   ;//no -> ready
  274.     mov ax,currentfloptime
  275.     add ax,250                  ;//yes -> lower speed and try again
  276.     mov currentfloptime,ax
  277.   jmp synchroback
  278.  
  279. fertig:
  280.   mov al,34h                    ;//set Systemtimer right (Monoflop)
  281.   out 43h,al
  282.   mov ax, currentfloptime
  283.   sub ax,800                    ;//...we need time for the handler
  284.   mov currentfloptime,ax
  285.   out 40h,al
  286.   mov al,ah
  287.   out 40h,al
  288.  
  289.   xor ax,ax                     ;//redirect Int. 08 to Screenswitch Routine
  290.   mov es,ax
  291.   mov di,08h*4
  292.   cli
  293.   cld
  294.   mov ax,offset switchpageint   ;//interrupt handler routine see below
  295.   stosw
  296.   mov ax,cs
  297.   stosw
  298.   sti
  299.   pop di
  300.   ret
  301. inittimer ENDP
  302.  
  303. closetimer PROC         ;// this routine de-installs the timer handler
  304.   push ds
  305.   push di
  306.   push si
  307.   cli
  308.   mov al,36h            ;//Systemtimer back to normal speed
  309.   out 43h,al
  310.   xor al,al
  311.   out 40h,al
  312.   out 40h,al
  313.   push cs               ;//restore Interrupt Vector back to normal
  314.   pop ds
  315.   mov si,offset alterint08
  316.   xor ax,ax
  317.   mov es,ax
  318.   mov di,08h*4
  319.   cld
  320.   movsw
  321.   movsw
  322.   sti
  323.   pop si
  324.   pop di
  325.   pop ds
  326.   ret
  327. closetimer ENDP
  328. ************************************
  329.  
  330.  
  331. *** 2.2.2 The interrupt Handler routine
  332.  
  333. This is the main timer interrupt routine which is called after every screen
  334. update and performs the page flipping.
  335. There are three necessary things when you write a hardware interrupt handler:
  336. 1) be sure to preserve ALL registers you use (push them and pop them later)!
  337. 2) don't forget to acknowledge the hardware interrupt controller 
  338.     (mov al,20h   out 20h,al)!
  339. 3) return from Interrupt with IRET, not with RET!
  340.  
  341. Read the comments; they should explain everything.
  342. Literature used for this: [2], [3]
  343.  
  344. ************************************
  345. switchpageint PROC
  346.   push ax                       ;//interrupt handlers must push all registers
  347.   push bx                       ;//they use!
  348.   push dx
  349.  
  350.   inc word ptr systimer         ;//set system timer (this is my own timer;
  351.                 ;//i use it for timing in the main program)
  352.   mov bx,currentpage
  353.   add bx,32768
  354.   mov currentpage,bx
  355.   mov dx,3d4h
  356.   mov al,0ch                    ;//set Start Adresse High (0Ch) to flip pages
  357.   mov ah,bh
  358.   out dx,ax
  359.  
  360.   mov dx,3dah                   ;//Wait for Retrace
  361. swretjmp:                       ;//(this is done to keep synchronization)
  362.     in al,dx
  363.     and al,00001000b
  364.   jz swretjmp
  365.  
  366.   mov al,34h                    ;//start Monoflop for new
  367.   out 43h,al                    ;//(let the timer run for new)
  368.   mov ax,currentfloptime
  369.   out 40h,al
  370.   mov al,ah
  371.   out 40h,al
  372.  
  373.   mov bx,currentsystimer        ;//do Systemtimer call at 18.2 Hz
  374.   add ax,bx
  375.   mov currentsystimer,ax
  376.   cmp ax,bx
  377.   ja short nosysroutine         ;//No --> continue
  378.   pop dx
  379.   pop bx
  380.   pop ax
  381.   jmp dword ptr alterint08      ;//call Systemtimer Routine
  382. nosysroutine:
  383.   mov al,20h                    ;//OK to Interrupt Controller
  384.   out 20h,al
  385.  
  386.   pop dx
  387.   pop bx
  388.   pop ax
  389.   iret                          ;//return from interrupt
  390. switchpageint ENDP
  391. ************************************
  392.  
  393. There may be timing problems when you use your own hardware interrupt handler.
  394. Especially the INT 13h calls are very time-sensitive, if a timer interrupt
  395. routine is called just when the processor is in INT13 handler, and the com-
  396. puting of the timer int takes too long, the computer may crash.
  397. In such cases it may help to check if the computer is just in the INT13 hand-
  398. ler when the timer interrupt is called (You have to hook int 13 and set a
  399. variable; then continue with int13 handler. After the handler has finished,
  400. reset the variable. So the timer int can check this variable to see if INT13
  401. handler is active or not.)
  402. Well, I never had problems with INT13 and FakeMode, so I didn't implement
  403. this. :)
  404.  
  405.  
  406. *** 2.3 Palette Setup
  407.  
  408. The palette is static; that means I don't change it when I flip pages.
  409. To achieve the 3840 color mode, I split up the colors to green and red/blue.
  410. The palette contains 16*15 values red/blue and 16 values green (16*15+16=256).
  411. (16 colors red * 16 colors green * 15 colors blue = 3840 different colors)
  412. To get harmonic greys, I set blue to the same values as red and green, but
  413. just leave out the darkest blue value (you can't see that one, anyway).
  414. So when you set pixels later, you have to decrement the blue value if it
  415. isn't zero to get the right color. (The H_setsmallpixel routine of the
  416. example file included does that, for example.)
  417. The palette values are stored directly to DAC, but are also buffered in
  418. 'palette' to make later changes possible (fadein/out, setluminance).
  419.  
  420.  
  421. Here comes the palette setup routine:
  422.  
  423. ************************************
  424. palette db 768 dup (?)          ;//buffer for palette
  425.  
  426. initpalette PROC
  427.   push di
  428.   push cs
  429.   pop es
  430.   mov di, offset palette
  431.   cld
  432.   mov dx,3c8h
  433.   xor ax,ax
  434.   xor bx,bx
  435.   out dx,al
  436.   inc dx                ;//ah=red, bh=green, bl=blue
  437.   mov cx,15
  438. initpal_outer:          ;//setup red/blue part of palette (0..239)
  439.   push cx
  440.   mov cx,16
  441.   initpal_inner:
  442.       mov al,ah
  443.       out dx,al
  444.       stosb
  445.       mov al,bh
  446.       out dx,al
  447.       stosb
  448.       mov al,bl
  449.       out dx,al
  450.       stosb
  451.  
  452.       add ah,4
  453.     loop initpal_inner
  454.     mov ah,0
  455.     add bl,4
  456.     cmp bl,4
  457.     jne goon
  458.       add bl,4
  459.   goon:
  460.     pop cx
  461.   loop initpal_outer
  462.  
  463.   mov cx,16
  464.   xor ax,ax
  465.   xor bx,bx
  466. initpal_second:                 ;//setup green part of palette (240..255)
  467.     mov al,ah
  468.     out dx,al
  469.     stosb
  470.     mov al,bh
  471.     out dx,al
  472.     stosb
  473.     mov al,bl
  474.     out dx,al
  475.     stosb
  476.     add bh,4
  477.   loop initpal_second
  478.   pop di
  479.   ret
  480. initpalette ENDP
  481. ************************************
  482.  
  483.  
  484. *** How to set pixels in FakeMode
  485.  
  486. The main purpose of the way I set pixels is to minimize the flicker.
  487. One pixel on the screen consists of 2 pixels, one on page 1 and one on
  488. page 2. On one of the pages the green value is displayed, on the other
  489. the red/blue value.
  490. Imagine I would set all pixels green values on page 1 and all red/blue
  491. values on page 2. I would get horrible flicker. To prevent this, I set
  492. the values like follows:
  493.  
  494.   if xpos+ypos=odd, then set red/blue on page 1 and green on page 2
  495.             else set green on page 1 and red/blue on page 2.
  496.  
  497. So I get a 1/1 raster, and each of the 2 pages contain both red/blue and
  498. green values. Look at the following routine to see how it is done exactly:
  499.  
  500.  
  501. ************************************
  502. _F_putsmallpixel PROC
  503. ;//values:  x=0..319, y=0..399, red=0..15, green=0..15, blue=0..15
  504.   ARG x:word, y:word, red:byte, green:byte, blue:byte
  505.   push bp
  506.   mov bp,sp
  507.   push di
  508.   mov bx,x
  509.   mov cx,bx
  510.   and cl,00000011b      ;//calculate bitplane...
  511.   mov dx,3c4h
  512.   mov ax,0102h
  513.   shl ah,cl
  514.   out dx,ax             ;//...and set it
  515.   mov ax,0a000h         ;//set destination segment
  516.   mov es,ax
  517.   mov ax,160            ;//set destination offset
  518.   mov dx,y
  519.   mul dx
  520.   shr bx,1
  521.   and bl,11111110b
  522.   add bx,ax             ;//bx contains basic offset
  523.   mov di,bx
  524.   mov al,blue           ;//calculate red-blue value
  525.   mov ah,16
  526.   mul ah
  527.   cmp ax,0
  528.   je short smallpixgoon
  529.     sub ax,16           ;// perform blue adjustment
  530. smallpixgoon:
  531.   add al,red
  532.   add cx,y
  533.   and cl,00000001b      ;// select if green value on page 1 or 2
  534.   jz short stypetwo
  535.     mov ah,al
  536.     mov al,green
  537.     add al,240
  538.     mov es:[di],ax      ;// set both pixels (on page 1 & 2)
  539.     jmp short send
  540. stypetwo:
  541.     mov ah,green
  542.     add ah,240
  543.     mov es:[di],ax      ;// set both pixels (on page 1 & 2)
  544. send:
  545.   pop di
  546.   pop bp
  547.   ret
  548. _F_putsmallpixel ENDP
  549. ************************************
  550.  
  551.  
  552. In FakeMode the video memory is built up like this:
  553.  
  554. Bitplane 0|  rb 0 | g  0 | g  4 | rb 4 | ...
  555. Bitplane 1|  g  1 | rb 1 | rb 5 | g  5 | ...
  556. Bitplane 2|  rb 2 | g  2 | g  6 | rb 6 | ...
  557. Bitplane 3|  g  3 | rb 3 | rb 7 | g  7 | ...
  558. Offset    |    0  |   1  |   2  |   3  | ...
  559.  
  560. So one line on the screen uses 160 bytes of data in each Bitplane.
  561. The colors values for one pixel are stored besides each other (this is
  562. because I use wordmode).
  563.  
  564.  
  565. -------------------------------------------------
  566. CHAPTER 3: Information about the program included
  567. -------------------------------------------------
  568.  
  569. With this doc comes an example program, written in BC 3.1 and TASM 3.1 .
  570. I also included the .PRJ file. (If the .PRJ file causes problems, create your 
  571. own: Just be sure to include both FAKESHOW.CPP and FAKEMODE.ASM in your 
  572. project and don't forget to set code generation to large.)
  573. There is also an example .TGA picture included (320x200, 24bit colors).
  574. This .TGA viewer will definitely only show UNPACKED 24-BIT .TGA pictures!
  575. (Perhaps you can extend this, but I considered it to be too much work for
  576. a little doc example). The viewer may display some of the .TGA pictures
  577. upside down; this is because the data is stored sometimes upside
  578. down. (I think there is a flag for this in the header of the .TGA).
  579. The file FAKEMODE.ASM is my complete FakeMode routine library and contains
  580. all useful basic routines concerning FakeMode.
  581.  
  582.  
  583. ---------------------
  584. CHAPTER 4: Literature
  585. ---------------------
  586.  
  587. [1]: Michael Tischer: PC intern 3.0; Data Becker  (a german book)
  588.             Contains useful information about VGA programming
  589.             (Although the Ferraro book might be better)
  590.  
  591. [2]: DOS international, issue 3/89 p.170 ff; Everts&Hagedorn (german computer
  592.             magazine). This is an article about how sample output
  593.             with PC internal speaker is done. That's where I got
  594.             timer / interrupt programming from
  595.  
  596. [3]: A huge stack of copied sheets from several books I don't remember. :)
  597.  
  598.  
  599. ----------------------------------------------------------------------------
  600.  
  601. So, I think this is enough. I hope you will be able to program FakeMode with
  602. this doc. If you haven't understood yet how FakeMode works, take a look at  
  603. source in the example program.
  604. If you want to see what effects are possible with FakeMode, have a look at
  605. Xography's "Party'93 Report"...  (You may find it in the internet on
  606. WASP.ENG.UFL.EDU, in /pub/msdos/demos/alpha/x, xgy_pr93.zip).
  607.  
  608.  
  609. (Oh, by the way: You can greet me in your FakeMode productions if you want :)
  610.  
  611. Cheers,
  612.       Yaka/Xography
  613.  
  614.  
  615.  
  616.  
  617. P.S.: If you have additional questions or suggestions, you can EMail to:
  618.             uke4@rzstud1.rz.uni-karlsruhe.de
  619.  
  620.   (Please only send important messages, I don't want to have my mailbox
  621.    flooded with "how-can-I-do-this"'s and "how-can-I-do-that"'s...
  622.    And remember, I haven't got the time to answer all letters I receive, 
  623.    but I will try to read them all.)
  624.